import agent
import random
import time
from agent import Feedback
import nltk

class rhymeAgent(agent.Agent):
	"""
    """
	def __init__(self, name):
		self.framing = "" #framing information used for feedback
		p = 1.0/26 #initial likelihood of existance of each letter in a "nice" word
		self.likelihood = dict(a=p,b=p,c=p,d=p,e=p,f=p,g=p,h=p,i=p,j=p,k=p,l=p,m=p,n=p,o=p,p=p,q=p,r=p,s=p,t=p,u=p,v=p,w=p,x=p,y=p,z=p)
		self.niceness_threshold = 0.02 #minimum average likelihood of each letter in a word for it to be considered "nice"
		self.niceness_point = 0.001 #point(or additionl likelihood) given to a letter when the phrase containing it has received possitive feedback from other agents
		self.max_adapt_feedbackCheck = 5 #max number of feedback to check in adaptation phase (adapt)
		agent.Agent.__init__(self, name)
		
	def lifeCycle(self):
		"""
		The function which is repeatedly started and defines the behaviour
		of the agent in the context of adaption, scoring and generating.
		"""
		r = random.random()
		if r >= 0.6:
			for i in range(0,5):
				self.generate()
		elif 0.2< r < 0.6:
			unratedwords = self.getUnscoredWords()
			if len(unratedwords) > 0:
				num = min(5,len(unratedwords))
				for i in range(0,num):
					scr = self.score(unratedwords[i].word)
					if scr < 0.2:
						framingTemp = "The rhyme in this phrase is not nice or it is not an English phrase; " 
					elif scr <= 0.4:
						framingTemp = "The rhyme in this phrase is decent; "
					elif scr <= 0.6:
						framingTemp = "The rhyme in this phrase is nice; "
					elif scr > 0.6:
						framingTemp = "The rhyme in this phrase is very nice; "
					self.framing = framingTemp + self.framing
					framingTemp = self.framing
					self.framing = ""
					self.sendFeedback(unratedwords[i].word_id, scr, framingTemp, wordtext=unratedwords[i].word)
		else:
			feedback = self.getAllFeedback()
			feedback = sorted(feedback, key=lambda x: x.timestamp, reverse=True)
			self.adapt(feedback)
		
	def score(self, phrase):
		"""
		"""
		maxScr = scr = 0
		words = phrase.split(' ')
		if len(words)<2 or words[0]==words[1]:
			return 0
		wordsNum = len(words)
		for i in range(0,wordsNum-1):
			for j in range(i+1,wordsNum):
				endingRhyme = self.callFunction('MeysamM_endingRhyme', words[i]+' '+words[j])
				if endingRhyme>=2:
					self.framing += " I find the attribute MeysamM_endingRhyme to be too high ," 
				beginningRhyme = self.callFunction('MeysamM_beginningRhyme', words[i]+' '+words[j])
				if beginningRhyme>=2:
					self.framing += " I find the attribute MeysamM_beginningRhyme to be too high ," 
				scr = scr + endingRhyme + beginningRhyme
				if scr>maxScr:
					maxScr = scr
		maxScr = 0.2 * maxScr
		if maxScr == 0 :
			matchingLetters = self.callFunction('MeysamM_matchingLetters', phrase)
			if matchingLetters>2:
				self.framing += " I find the attribute MeysamM_matchingLetters to be too high ,"
			else:
				self.framing += " I find the attribute MeysamM_matchingLetters to be too low , and I find the attribute MeysamM_endingRhyme to be too low , I find the attribute MeysamM_beginningRhyme to be too low "
			maxScr = (matchingLetters-1)*0.2
		if maxScr > 1:
			maxScr = 1
		if maxScr < 0:
			maxScr= 0 

		return maxScr
		
	def generate(self):
		"""
		"""		
		r = random.random()
		
		if r<0.4:
			self.generate_endingRhyme()
		elif 0.4<=r and r<0.8:
			self.generate_beginningRhyme()
		else:
			self.generate_matchingLetters()
			
	def generate_endingRhyme(self):
		entries = nltk.corpus.cmudict.entries()
		nice = 0
		while not nice:			
			randIndex = random.randint(0,len(entries)-1)
			firstWord = entries[randIndex]
			nice = self.nice_letter_selection(firstWord[0])
		syllableRange = (2,4)
		syllableLen = random.randint(syllableRange[0],min(syllableRange[1],len(firstWord[1])))
		wordsList = [word for word in entries if word[1][-syllableLen:]==firstWord[1][-syllableLen:]]
		secondWord = wordsList[random.randint(0,len(wordsList)-1)]
		if firstWord[0]==secondWord[0]:
			return
		phrase = firstWord[0] + ' ' + secondWord[0]
		explanation = "I find the attribute ending rhyme to be as high as I prefer"
		self.propose(phrase, explanation)
			
			
	def generate_beginningRhyme(self):
		entries = nltk.corpus.cmudict.entries()
		nice = 0
		while not nice:			
			randIndex = random.randint(0,len(entries)-1)
			firstWord = entries[randIndex]
			nice = self.nice_letter_selection(firstWord[0])
		syllableRange = (2,4)
		syllableLen = random.randint(syllableRange[0],min(syllableRange[1],len(firstWord[1])))
		wordsList = [word for word in entries if word[1][:syllableLen]==firstWord[1][:syllableLen]]
		secondWord = wordsList[random.randint(0,len(wordsList)-1)]
		if firstWord[0]==secondWord[0]:
			return
		phrase = firstWord[0] + ' ' + secondWord[0]
		explanation = "I find the attribute beginning rhyme to be as high as I prefer"
		self.propose(phrase, explanation)
		
		
	def generate_matchingLetters(self):
		entries = nltk.corpus.cmudict.entries()
		nice = 0
		while not nice:			
			randIndex = random.randint(0,len(entries)-1)
			firstWord = entries[randIndex]
			nice = self.nice_letter_selection(firstWord[0])
		vowels = "aeiou"
		vowelLetters = consonantLetters = ""
		firstWord = firstWord[0]
		for letter in firstWord:
			if letter in vowels:
				vowelLetters += letter
			else:
				consonantLetters += letter
		if random.randint(0,1) and len(vowelLetters)>=2:
			#generate maching vowels phrase
			letterIndex = sorted( random.sample( range(0,len(vowelLetters)) , random.randint(2,min(4,len(vowelLetters))) ) )
			letters = [vowelLetters[i] for i in letterIndex]
		elif (len(consonantLetters)>=2):
			#generate maching consonants phrase
			letterIndex = sorted( random.sample( range(0,len(consonantLetters)) , random.randint(2,min(4,len(consonantLetters))) ) )
			letters = [consonantLetters[i] for i in letterIndex]
		else:
			return
	
		secondWord = []
		for word,syll in entries:
			l = w = count = 0
			while l<len(letters) and w<len(word):
				if letters[l]==word[w]:
					count += 1
					w += 1
					l += 1
				w += 1
			if count==len(letters):
				secondWord.append(word)
					
		if secondWord!=[]:
			secondWord = secondWord[random.randint(0,len(secondWord)-1)]
		else:
			return
		if firstWord==secondWord:
			return
		phrase = firstWord + ' ' + secondWord
		explanation = "I find the attribute matching letters to be as high as I prefer"
		self.propose(phrase, explanation)
		
	
	def nice_letter_selection(self, word):
		sum_likelihood = 0.0
		for l in word:
			if l in self.likelihood.keys():
				sum_likelihood += self.likelihood[l]		
		if (sum_likelihood/len(word)) >= self.niceness_threshold:
			return 1 #word is "nice" considering the comprising letters
		return 0
		
		
	def adapt(self, feedback):
		"""
		"""
		count = 0
		for feeds in feedback:
			if count > self.max_adapt_feedbackCheck:
				break
			if self.id == feeds.creator_agent_id:
				count += 1
				if feeds.score >= 0.4:
					
					#add the niceness likelihood of words containing these letters
					words = feeds.word.split();
					for w in words:
						for l in self.likelihood.keys():
							if l in w:
								self.likelihood[l] += self.niceness_point * (len(w.split(l))-1) #adding niceness point
							else:
								self.likelihood[l] -= (self.niceness_point*len(w)) / (len(self.likelihood)-len(w)) #deducting niceness point
					print "I changed the word niceness criterion according to feedback from agent: " + feeds.scoring_agent_id
					
					bias = (1-sum(self.likelihood.values())) / len(self.likelihood)
					for l in self.likelihood:
						self.likelihood[l] += bias
